﻿using System;
using GeoAPI.Geometries;

namespace YJKGridTopologyCal.Operation.Buffer.Validate
{
	public class BufferResultValidator
	{
		public static bool IsValid(IGeometry g, double distance, IGeometry result)
		{
			return new BufferResultValidator(g, distance, result).IsValid();
		}

		public static string IsValidMessage(IGeometry g, double distance, IGeometry result)
		{
			BufferResultValidator bufferResultValidator = new BufferResultValidator(g, distance, result);
			if (!bufferResultValidator.IsValid())
			{
				return bufferResultValidator.ErrorMessage;
			}
			return null;
		}

		public BufferResultValidator(IGeometry input, double distance, IGeometry result)
		{
			this._input = input;
			this._distance = distance;
			this._result = result;
		}

		public bool IsValid()
		{
			this.CheckPolygonal();
			if (!this._isValid)
			{
				return this._isValid;
			}
			this.CheckExpectedEmpty();
			if (!this._isValid)
			{
				return this._isValid;
			}
			this.CheckEnvelope();
			if (!this._isValid)
			{
				return this._isValid;
			}
			this.CheckArea();
			if (!this._isValid)
			{
				return this._isValid;
			}
			this.CheckDistance();
			return this._isValid;
		}

		public string ErrorMessage
		{
			get
			{
				return this._errorMsg;
			}
		}

		public Coordinate ErrorLocation
		{
			get
			{
				return this._errorLocation;
			}
		}

		public IGeometry ErrorIndicator
		{
			get
			{
				return this._errorIndicator;
			}
		}

		private void Report(string checkName)
		{
			bool verbose = BufferResultValidator.Verbose;
		}

		private void CheckPolygonal()
		{
			if (!(this._result is IPolygon) && !(this._result is IMultiPolygon))
			{
				this._isValid = false;
			}
			this._errorMsg = "Result is not polygonal";
			this._errorIndicator = this._result;
			this.Report("Polygonal");
		}

		private void CheckExpectedEmpty()
		{
			if (this._input.Dimension >= Dimension.Surface)
			{
				return;
			}
			if (this._distance > 0.0)
			{
				return;
			}
			if (!this._result.IsEmpty)
			{
				this._isValid = false;
				this._errorMsg = "Result is non-empty";
				this._errorIndicator = this._result;
			}
			this.Report("ExpectedEmpty");
		}

		private void CheckEnvelope()
		{
			if (this._distance < 0.0)
			{
				return;
			}
			double num = this._distance * 0.012;
			if (num == 0.0)
			{
				num = 0.001;
			}
			Envelope envelope = new Envelope(this._input.EnvelopeInternal);
			envelope.ExpandBy(this._distance);
			Envelope envelope2 = new Envelope(this._result.EnvelopeInternal);
			envelope2.ExpandBy(num);
			if (!envelope2.Contains(envelope))
			{
				this._isValid = false;
				this._errorMsg = "Buffer envelope is incorrect";
				this._errorIndicator = this._result;
			}
			this.Report("Envelope");
		}

		private void CheckArea()
		{
			double area = this._input.Area;
			double area2 = this._result.Area;
			if (this._distance > 0.0 && area > area2)
			{
				this._isValid = false;
				this._errorMsg = "Area of positive buffer is smaller than input";
				this._errorIndicator = this._result;
			}
			if (this._distance < 0.0 && area < area2)
			{
				this._isValid = false;
				this._errorMsg = "Area of negative buffer is larger than input";
				this._errorIndicator = this._result;
			}
			this.Report("Area");
		}

		private void CheckDistance()
		{
			BufferDistanceValidator bufferDistanceValidator = new BufferDistanceValidator(this._input, this._distance, this._result);
			if (!bufferDistanceValidator.IsValid())
			{
				this._isValid = false;
				this._errorMsg = bufferDistanceValidator.ErrorMessage;
				this._errorLocation = bufferDistanceValidator.ErrorLocation;
				this._errorIndicator = this._result;
			}
			this.Report("Distance");
		}

		public static bool Verbose;

		private const double MaxEnvDiffFrac = 0.012;

		private readonly IGeometry _input;

		private readonly double _distance;

		private readonly IGeometry _result;

		private bool _isValid = true;

		private string _errorMsg;

		private Coordinate _errorLocation;

		private IGeometry _errorIndicator;
	}
}
